package com.sys.utils;

import com.alibaba.fastjson.JSONObject;
import com.sys.entity.SysUser;
import com.bhudy.exception.SysException;
import com.bhudy.exception.SysExceptionCode;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SessionKey;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.DefaultSubjectContext;
import org.apache.shiro.web.session.mgt.WebSessionKey;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.Serializable;
import java.util.Map;

/**
 * @Author com.bhudy
 * @Description Shiro登陆的方法的工具类
 * @Date 2019-10-30 23:09:37
 */
public final class ShiroUtils {

    private ShiroUtils() {
    }

    /**
     * 验证角色
     *
     * @param roles
     * @return
     */
    public static boolean hasRoles(String... roles) {
        if (roles == null || roles.length == 0) return false;
        Subject subject = getSubjct();
        if (subject == null) return false;

        for (String role : roles) {
            if (subject.hasRole(role)) return true;
        }
        return false;
    }

    /**
     * 获取getSubjct
     *
     * @return Subject
     */
    public static Subject getSubjct() {
        try {
            return SecurityUtils.getSubject();
        } catch (Exception e) {
            return null;
        }

    }

    /**
     * 获取用户信息
     * 优先从Subject中获取用户信息
     * 如果没有就根据sessionId获取用户信息
     *
     * @return User 或者 null
     */
    public static SysUser getUser() {
        Subject subject = getSubjct();
        if (subject == null) return null;
        Object object = subject.getPrincipal();
        if (object == null) {
            return getUser(getSessionId());
        } else {
            return (SysUser) object;
        }
    }

    /**
     * 获取用户的Id
     *
     * @return userId 或者 null
     */
    public static Long getUserId() {
        SysUser user = getUser();
        if (user == null || user.getUserId() == null) {
            return null;
        } else {
            return user.getUserId();
        }
    }

    /**
     * 获取用户的Id
     *
     * @return userId 或者 null
     */
    public static Long getResPersonalId() {
        SysUser user = getUser();
        if (user == null || user.getSysPersonalId() == null) {
            return null;
        } else {
            return user.getSysPersonalId();
        }
    }

    /**
     * 获取sessionId
     *
     * @return String
     */
    public static String getSessionId() {
        return (String) getSubjct().getSession().getId();
    }

    /**
     * 退出登录
     */
    public static void logout() {
        getSubjct().logout();
    }

    /**
     * 根据sessionid 获取用户信息
     * 方法重写
     *
     * @param sessionID
     * @return SysUser
     */
    public static SysUser getUser(String sessionID) {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
            return ShiroUtils.getUser(sessionID, request, response);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 根据sessionid 获取用户信息
     *
     * @param sessionID sessionID
     * @param request   HttpServletRequest
     * @param response  HttpServletResponse
     * @return SysUser
     */
    public static SysUser getUser(String sessionID, HttpServletRequest request, HttpServletResponse response) {
        SessionKey key = new WebSessionKey(sessionID, request, response);
        Session se = SecurityUtils.getSecurityManager().getSession(key);
        Object obj = se.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);

        SimplePrincipalCollection coll = (SimplePrincipalCollection) obj;
        SysUser sysUser = (SysUser) coll.getPrimaryPrincipal();

        if (sysUser != null) {
            SysUser user = (SysUser) se.getAttribute("user");
            if (user == null) {
                se.setAttribute("user", sysUser);
            }
            return sysUser;
        } else {
            return null;
        }

    }

    /**
     * 方法重写
     * 优先从cookie中获取access_token
     * 如果没有就从headers请求头中获取access_token
     * 获取到access_token就解密
     *
     * @return access_token解密得到的数据
     * Map<String, String> cookieMap = JSONObject.parseObject(AesCBCUtil.decrypt(AesCBCUtil.decrypt(access_token)), Map.class);
     * cookieMap.put("userAgent", request.getHeader("user-agent"));
     * cookieMap.put("remoteAddr", request.getRemoteAddr());
     * cookieMap.put("uuid",  UUID.randomUUID().toString());
     * cookieMap.put("sessionId", ShiroUtils.getSessionId());
     */
    public static Map<String, String> getToken() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
            return getToken(request, response);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 优先从cookie中获取access_token
     * 如果没有就从headers请求头中获取access_token
     * 获取到access_token就解密
     *
     * @param request  HttpServletRequest
     * @param response HttpServletResponse
     * @return access_token解密得到的数据
     * Map<String, String> cookieMap = JSONObject.parseObject(AesCBCUtil.decrypt(AesCBCUtil.decrypt(access_token)), Map.class);
     * cookieMap.put("userAgent", request.getHeader("user-agent"));
     * cookieMap.put("remoteAddr", request.getRemoteAddr());
     * cookieMap.put("uuid",  UUID.randomUUID().toString());
     * cookieMap.put("sessionId", ShiroUtils.getSessionId());
     */
    public static Map<String, String> getToken(HttpServletRequest request, HttpServletResponse response) {
        String access_token = null;
        if (access_token == null || access_token.equals("")) {
            access_token = Utils.getAccessToken();
        }

        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals("access_token")) {
                    access_token = cookie.getValue();
                }
            }
        }
        if (access_token == null || access_token.equals("")) {
            return null;
        }

        Map<String, String> cookieMap = JSONObject.parseObject(AesCBCUtil.decrypt(AesCBCUtil.decrypt(access_token)), Map.class);
        if (cookieMap == null || !request.getHeader("user-agent").equals(cookieMap.get("userAgent")) || !request.getRemoteAddr().equals(cookieMap.get("remoteAddr"))) return null;

        return cookieMap;
    }
}
